package com.hung.triple.registry.nacos;

import com.alibaba.nacos.api.config.ConfigFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingFactory;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.listener.EventListener;
import com.alibaba.nacos.api.naming.listener.NamingEvent;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.hung.triple.bootstrap.config.TripleRegistryConfig;
import com.hung.triple.common.enums.RpcError;
import com.hung.triple.common.exception.TripleRpcException;
import com.hung.triple.consumer.ConsumerBeanInfo;
import com.hung.triple.context.RpcRuntimeContext;
import com.hung.triple.loadbalancer.RandomLoadBalancer;
import com.hung.triple.registry.ProviderAddressPool;
import com.hung.triple.registry.ProviderBeanInfo;
import lombok.SneakyThrows;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author Hung
 * @date 2022/9/24 23:01
 */
public class NacosUtil {

    /**
     * 注册中心地址
     */
    private static final String SERVER_ADDRESS = RandomLoadBalancer.selectOne(TripleRegistryConfig.getAddressList());
    private static Logger logger = LoggerFactory.getLogger(NacosUtil.class);
    /**
     * 官方的两个API接口，对应命名服务和配置服务
     */
    private static NamingService namingService;
    private static ConfigService configService;

    static {
        try {
            namingService = NamingFactory.createNamingService(SERVER_ADDRESS);
            configService = ConfigFactory.createConfigService(SERVER_ADDRESS);
        } catch (NacosException e) {
            logger.error("连接到Nacos时有错误发生: ", e);
            throw new TripleRpcException(String.valueOf(RpcError.FAILED_TO_CONNECT_TO_SERVICE_REGISTRY));
        }
    }

    public static void registerService(String serviceName, String groupName, String version, InetSocketAddress address) throws NacosException {
        //组装instance 实例
        Instance instance = new Instance();
        instance.setClusterName("DEFAULT");
        instance.setIp(address.getAddress().getHostAddress());
        instance.setPort(address.getPort());
        instance.setWeight(1.0);

        //注册到RpcRuntimeContext


        //注册
        namingService.registerInstance(serviceName, groupName, instance);
    }

    public static void registerService(ProviderBeanInfo providerInfo, InetSocketAddress address) throws NacosException {
        //组装instance 实例
        Instance instance = new Instance();
        instance.setClusterName("DEFAULT");
        instance.setIp(address.getAddress().getHostAddress());
        instance.setPort(address.getPort());
        instance.setWeight(1.0);

        providerInfo.setInstance(instance);

        //注册到RpcRuntimeContext
        RpcRuntimeContext.cacheProviderConfig(providerInfo);

        //注册
        namingService.registerInstance(providerInfo.getServiceName(), providerInfo.getGroupName(), instance);
    }


    public static void subscribe(ConsumerBeanInfo consumerBeanInfo) {
        //默认监听器
        EventListener eventListener = event -> {
            if (event instanceof NamingEvent) {
                NamingEvent namingEvent = (NamingEvent) event;
                //获取到所有的实例
                List<Instance> instances = namingEvent.getInstances();
                if (instances == null) {
                    instances = new ArrayList<>();
                }
                //去除没有启动的实例
                instances.removeIf(i -> !i.isEnabled());
                //ip:port 组合
                Set<String> instancesAddress = instances.stream()
                        .map(instance1 -> instance1.getIp() + ":" + instance1.getPort())
                        .collect(Collectors.toSet());
                //TODO 这里只对ProviderAddressPool做了修改，TransporterPool也有要不要修改？
                ProviderAddressPool.namingEventHandler(consumerBeanInfo.getGroupName(), consumerBeanInfo.getServiceName(), consumerBeanInfo.getVersion(), instancesAddress);
            }
        };
        consumerBeanInfo.setEventListener(eventListener);
        RpcRuntimeContext.cacheConsumerConfig(consumerBeanInfo);
        subscribe(consumerBeanInfo.getGroupName(), consumerBeanInfo.getServiceName(), consumerBeanInfo.getVersion(), eventListener);
    }

    @SneakyThrows
    public static void subscribe(String serviceName, String groupName, String version, EventListener eventListener) {
        namingService.subscribe(serviceName, groupName, eventListener);
    }

    @SneakyThrows
    public static void deRegisterService(String serviceName, String groupName, String version, Instance instance) {
        namingService.deregisterInstance(serviceName, groupName, instance);
    }

    @SneakyThrows
    public static void deSubscribe(String serviceName, String groupName, String version, EventListener eventListener) {
        namingService.unsubscribe(serviceName, groupName, eventListener);
    }

    @SneakyThrows
    public static void deSubscribe(ConsumerBeanInfo consumerBeanInfo) {
        namingService.unsubscribe(consumerBeanInfo.getServiceName(), consumerBeanInfo.getGroupName(), consumerBeanInfo.getEventListener());
    }

    public static List<Instance> getAllInstance(String serviceName, String groupName, String version) throws NacosException {
        return namingService.getAllInstances(serviceName, groupName);
    }

//    public void clearRegistry() {
//        if (!serviceNames.isEmpty() && address != null) {
//            String host = address.getHostName();
//            int port = address.getPort();
//            for (String serviceName : serviceNames) {
//                try {
//                    namingService.deregisterInstance(serviceName, host, port);
//                } catch (NacosException e) {
//                    logger.error("注销服务 {} 失败", serviceName, e);
//                }
//            }
//        }
//    }

}
